/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package servlets;

import connection.DBConnection;
import dto.Look;

import java.io.*;
import java.sql.*;
import java.util.logging.*;
import java.util.*;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.XMLConstants;
import javax.xml.bind.*;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import dto.LookDetail;
import dto.Looks;
import dto.TagDetail;
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.ocpsoft.prettytime.PrettyTime;
import org.xml.sax.SAXException;
import utilities.XMLUtilities;

/**
 * @author Tung An
 */
@WebServlet(name = "ProcessServlet", urlPatterns = {"/ProcessServlet"})
public class ProcessServlet extends HttpServlet {

    private PrettyTime prettyTime = new PrettyTime();

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/plain");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        String param = request.getParameter("action");
        try {
            if (param != null) {
                if (param.equalsIgnoreCase("getall")) {
                    out.write(this.getLook());
                } else if (param.equalsIgnoreCase("create")) {
                    Look look = this.createLookObj(request.getParameter("xml"));
                    this.insertLook(look);
                } else if (param.equalsIgnoreCase("upload")) {
                    String url = "create_look.jsp";
                    HttpSession session = request.getSession();
                    session.setAttribute("img", request.getParameter("imgLocation"));
                    RequestDispatcher rd = request.getRequestDispatcher(url);
                    rd.forward(request, response);
                } else if (param.equalsIgnoreCase("edit")) {
                    String url = "create_look.jsp?look=" + request.getParameter("lookId") + "&edit=true";
                    HttpSession session = request.getSession();
                    session.setAttribute("img", request.getParameter("imgLocation"));
                    session.setAttribute("lookId", request.getParameter("lookId"));
                    response.sendRedirect(url);
                } else if (param.equalsIgnoreCase("getlookimage")) {
                    Integer lookId = Integer.parseInt(request.getParameter("lookId"));
                    out.print("<img name='tagImage' src=\"" + this.getLookImage(lookId) + "\"></img>");
                } else if (param.equalsIgnoreCase("getlookdetail")) {
                    Integer lookId = Integer.parseInt(request.getParameter("lookId"));
                    out.print(this.getLookDetail(lookId));
                } else if (param.equalsIgnoreCase("imgURLUpload")) {
                    String imgLocation = request.getParameter("imgURL");
                    String fileName = XMLUtilities.saveImageFromURL(imgLocation, getServletContext().getRealPath("images/upload"));
                    out.print("<img name='tagImage' src=\"./images/upload/" + fileName + "\"></img>");
                } else if (param.equalsIgnoreCase("search")) {
                    String text = request.getParameter("text");
                    out.write(this.searchLook(text));
                }
            } else {
                String fileName = "";
                List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
                for (FileItem item : items) {
                    fileName = XMLUtilities.saveImage(item, getServletContext().getRealPath("images/upload"));
                }
                out.print("<img name='tagImage' src=\"./images/upload/" + fileName + "\"></img>");
            }

        } catch (
                FileUploadException ex
                )

        {
            Logger.getLogger(ProcessServlet.class.getName()).log(Level.SEVERE, null, ex);
        } finally

        {
            out.close();
        }

    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">

    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request  servlet request
     * @param response servlet response
     * @throws javax.servlet.ServletException if a servlet-specific error occurs
     * @throws java.io.IOException            if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request  servlet request
     * @param response servlet response
     * @throws javax.servlet.ServletException if a servlet-specific error occurs
     * @throws java.io.IOException            if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

    private String getLook() {
        StringWriter xmlWriter = new StringWriter();
        DBConnection con = new DBConnection("localhost", "root", "123456", "xml");
        String query = "SELECT * FROM looks, users WHERE looks.userID = users.userID";
        ResultSet rs = con.excuteQuery(query);
        try {
            Looks looks = new Looks();
            List<LookDetail> detailList = new ArrayList<LookDetail>();
            while (rs.next()) {
                LookDetail look = new LookDetail();
                look.setLookid(rs.getShort("lookID"));
                look.setLookname(rs.getString("lookName"));
                look.setUpdatetime(prettyTime.format(rs.getTimestamp("updateTime")));
                GregorianCalendar c = new GregorianCalendar();
                c.setTime(rs.getTimestamp("updateTime"));
                XMLGregorianCalendar date = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
                look.setOriginaltime(date);
                look.setLookimage(rs.getString("lookImage"));
                look.setLookdescription(rs.getString("lookDescription"));
                String avatarURL = "";
                if (rs.getString("avatarURL") != null) {
                    avatarURL = rs.getString("avatarURL");
                }
                look.setAvatarurl(avatarURL);
                look.setUsername(rs.getString("username"));
                look.setUserid(rs.getShort("userID"));
                detailList.add(look);
            }
            looks.setLook(detailList);
            try {
                JAXBContext ctx = JAXBContext.newInstance(Looks.class);
                Marshaller mar = ctx.createMarshaller();

                SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
                Schema schema = sf.newSchema(new File("/XML/schemas/looks.xsd"));
                mar.setSchema(schema);
                mar.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
                mar.marshal(looks, xmlWriter);
            } catch (JAXBException ex) {
                Logger.getLogger(ProcessServlet.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SAXException e) {
                e.printStackTrace();
            }

        } catch (SQLException ex) {
            Logger.getLogger(ProcessServlet.class.getName()).log(Level.SEVERE, null, ex);
        } catch (DatatypeConfigurationException e) {
            e.printStackTrace();
        }
        con.close();
        return xmlWriter.toString();
    }

    private String getLookDetail(Integer lookId) {
        StringWriter xmlWriter = new StringWriter();
        DBConnection con = new DBConnection("localhost", "root", "123456", "xml");
        try {
            String query = "SELECT * FROM looks,tags,users WHERE looks.lookID = tags.lookID AND looks.userID = users.userID AND looks.lookID=?";
            PreparedStatement st = con.prepareStatement(query);
            st.setInt(1, lookId);
            ResultSet rs = st.executeQuery();
            Look look = new Look();
            List<TagDetail> detailList = new ArrayList<TagDetail>();
            Look.Listtag listtag = new Look.Listtag();
            while (rs.next()) {
                TagDetail tag = new TagDetail();
                look.setUserid(rs.getShort("userID"));
                look.setUsername(rs.getString("username"));
                look.setAvatarurl(rs.getString("avatarURL"));
                look.setAddress(rs.getString("address"));
                look.setLookid(rs.getShort("lookID"));
                look.setLookname(rs.getString("lookName"));
                look.setLookimage(rs.getString("lookImage"));
                look.setUpdatetime(prettyTime.format(rs.getTimestamp("updateTime")));
                look.setLookdescription(rs.getString("lookDescription"));
                tag.setTagindex(rs.getShort("tagIndex"));
                tag.setCategory(rs.getShort("category"));
                tag.setTagname(rs.getString("tagName"));
                tag.setTagbrand(rs.getString("tagBrand"));
                tag.setTagstore(rs.getString("tagStore"));
                tag.setTagimage(rs.getString("tagImage"));
                tag.setTagstoreurl(rs.getString("tagURL"));
                tag.setLeft(rs.getShort("posX"));
                tag.setTop(rs.getShort("posY"));
                detailList.add(tag);
            }
            listtag.setTag(detailList);
            look.setListtag(listtag);
            try {
                JAXBContext ctx = JAXBContext.newInstance(Look.class);
                Marshaller mar = ctx.createMarshaller();
                mar.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
                mar.marshal(look, xmlWriter);
            } catch (JAXBException ex) {
                Logger.getLogger(ProcessServlet.class.getName()).log(Level.SEVERE, null, ex);
            }

        } catch (SQLException ex) {
            Logger.getLogger(ProcessServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
        con.close();
        return xmlWriter.toString();
    }

    private Look createLookObj(String xml) {
        if (xml.isEmpty()) {
            return null;
        }
        try {
            JAXBContext context = JAXBContext.newInstance(Look.class);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            InputStream stream = new ByteArrayInputStream(xml.getBytes());
            Look look = (Look) unmarshaller.unmarshal(stream);
            return look;
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    private String getLookImage(Integer lookId) {
        String imageURL = "";
        try {
            DBConnection con = new DBConnection("localhost", "root", "123456", "xml");
            String query = "SELECT * FROM looks WHERE lookID=?";
            PreparedStatement st = con.prepareStatement(query);
            st.setInt(1, lookId);
            ResultSet rs = st.executeQuery();
            if (rs.next()) {
                imageURL = rs.getString("lookImage");
                return imageURL;
            }
            con.close();
        } catch (SQLException ex) {
            Logger.getLogger(LoginServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    private void insertLook(Look look) {
        try {
            DBConnection con = new DBConnection("localhost", "root", "123456", "xml");
            String update = "UPDATE looks SET lookName = ?, lookDescription = ?, lookImage = ?, updateTime = now(), userID=? WHERE lookID=?";
            String query = "INSERT INTO looks (lookName, lookDescription, lookImage, updateTime, userID) VALUES (?,?,?,now(),?)";
            PreparedStatement st;
            if (look.getLookid() != 0) {
                st = con.prepareStatement(update);
                st.setInt(5, look.getLookid());
            } else {
                st = con.prepareStatement(query, true);
            }

            st.setString(1, look.getLookname());
            st.setString(2, look.getLookdescription());
            st.setString(3, look.getLookimage());
            st.setInt(4, look.getUserid());
            st.executeUpdate();
            if (look.getLookid() == 0) {
                ResultSet rs = st.getGeneratedKeys();
                if (rs != null && rs.next()) {
                    look.setLookid(rs.getShort(1));
                }
            }
            this.insertTag(look, con);
            con.close();
        } catch (SQLException ex) {
            Logger.getLogger(ProcessServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void insertTag(Look look, DBConnection con) {
        try {
            String query = "INSERT INTO tags (tagIndex, tagName, tagBrand, tagStore, tagURL, category, tagImage, posX, posY, lookID) VALUES (?,?,?,?,?,?,?,?,?,?)";
            String update = "UPDATE tags SET tagIndex = ?, tagName = ?, tagBrand = ?, tagStore = ?, tagURL =?, category = ?, tagImage = ?, posX = ?, posY = ?, lookID = ? WHERE tagIndex=? AND lookID=?";
            PreparedStatement st;
            for (int i = 0; i < look.getListtag().getTag().size(); i++) {
                TagDetail tag = look.getListtag().getTag().get(i);
                Boolean isExist = this.existingTag(tag.getTagindex(), look.getLookid());

                if (isExist) {
                    st = con.prepareStatement(update);
                    st.setInt(11, tag.getTagindex());
                    st.setInt(12, look.getLookid());
                } else {
                    st = con.prepareStatement(query);
                }

                st.setInt(1, tag.getTagindex());
                st.setString(2, tag.getTagname());
                st.setString(3, tag.getTagbrand());
                st.setString(4, tag.getTagstore());
                st.setString(5, tag.getTagstoreurl());
                st.setInt(6, tag.getCategory());
                st.setString(7, tag.getTagimage());
                st.setInt(8, tag.getLeft());
                st.setInt(9, tag.getTop());
                st.setInt(10, look.getLookid());
                st.executeUpdate();
            }
        } catch (SQLException ex) {
            Logger.getLogger(ProcessServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private Boolean existingTag(Short tagIndex, Short lookID) {
        Boolean result = false;
        try {
            DBConnection con = new DBConnection("localhost", "root", "123456", "xml");
            String query = "SELECT * FROM tags WHERE tagIndex=? AND lookID=?";
            PreparedStatement st = con.prepareStatement(query);
            st.setInt(1, tagIndex);
            st.setInt(2, lookID);
            ResultSet rs = st.executeQuery();
            if (rs.next()) {
                result = true;
            }
            con.close();
        } catch (SQLException ex) {
            Logger.getLogger(LoginServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }

    private String searchLook(String text) {
        StringWriter xmlWriter = new StringWriter();
        DBConnection con = new DBConnection("localhost", "root", "123456", "xml");
        String query = "SELECT * FROM looks, users WHERE looks.userID = users.userID AND looks.lookName like ?";
        PreparedStatement st = con.prepareStatement(query);
        try {
            st.setString(1, "%" + text + "%");
            ResultSet rs = st.executeQuery();
            try {
                Looks looks = new Looks();
                List<LookDetail> detailList = new ArrayList<LookDetail>();
                while (rs.next()) {
                    LookDetail look = new LookDetail();
                    look.setLookid(rs.getShort("lookID"));
                    look.setLookname(rs.getString("lookName"));
                    look.setUpdatetime(prettyTime.format(rs.getTimestamp("updateTime")));
                    look.setLookimage(rs.getString("lookImage"));
                    look.setLookdescription(rs.getString("lookDescription"));
                    String avatarURL = "";
                    if (rs.getString("avatarURL") != null) {
                        avatarURL = rs.getString("avatarURL");
                    }
                    look.setAvatarurl(avatarURL);
                    look.setUsername(rs.getString("username"));
                    look.setUserid(rs.getShort("userID"));
                    detailList.add(look);
                }
                looks.setLook(detailList);
                try {
                    JAXBContext ctx = JAXBContext.newInstance(Looks.class);
                    Marshaller mar = ctx.createMarshaller();

                    SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
                    Schema schema = sf.newSchema(new File("/XML/schemas/looks.xsd"));
                    mar.setSchema(schema);
                    mar.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
                    mar.marshal(looks, xmlWriter);
                } catch (JAXBException ex) {
                    Logger.getLogger(ProcessServlet.class.getName()).log(Level.SEVERE, null, ex);
                } catch (SAXException e) {
                    e.printStackTrace();
                }

            } catch (SQLException ex) {
                Logger.getLogger(ProcessServlet.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (SQLException e){
           e.printStackTrace();
        }
        con.close();
        return xmlWriter.toString();
    }
}